use redis::RedisError;

use super::imp_conf::{EtlStage, SourceType};
use std::{fmt::Debug, io};
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
    #[error(transparent)]
    Io(#[from] io::Error),
    #[error(transparent)]
    Yaml(#[from] serde_yaml::Error),
    #[error(transparent)]
    MySql(#[from] sqlx::Error),
    #[error(transparent)]
    Clickhouse(#[from] clickhouse_rs::errors::Error),
    #[error("{source_type}导入文件中的{import_name}配置出错:{msg}")]
    ImpConf {
        source_type: SourceType,
        import_name: String,
        msg: String,
    },
    #[error("解析文件{name}第{row}行第{col}列出错:{msg}")]
    StrConv {
        name: String,
        row: usize,
        col: usize,
        msg: String,
    },
    #[error("处理认定关系{name}出错:{msg}")]
    DiviProc { name: String, msg: String },
    #[error("在{stage}时执行SQL[{sql}]出错:{msg}")]
    Sql {
        stage: EtlStage,
        sql: String,
        msg: String,
    },
    #[error("BigTable文件:{file_name}中的{import_name}出错:{msg}")]
    BigTable {
        file_name: String,
        import_name: String,
        msg: String,
    },
    #[error(transparent)]
    Redis(#[from] RedisError),
    #[error(transparent)]
    Other(#[from] anyhow::Error),
}
impl Error {
    pub fn from_imp_conf(
        source_type: SourceType,
        import_name: impl AsRef<str>,
        msg: impl AsRef<str>,
    ) -> Self {
        Error::ImpConf {
            source_type,
            import_name: import_name.as_ref().to_owned(),
            msg: msg.as_ref().to_owned(),
        }
    }
    pub fn from_txt(name: impl AsRef<str>, row: usize, col: usize, msg: impl AsRef<str>) -> Self {
        Error::StrConv {
            name: name.as_ref().to_owned(),
            row,
            col,
            msg: msg.as_ref().to_owned(),
        }
    }
    pub fn from_divi_proc(name: impl AsRef<str>, msg: impl AsRef<str>) -> Self {
        Error::DiviProc {
            name: name.as_ref().to_owned(),
            msg: msg.as_ref().to_owned(),
        }
    }
    pub fn from_sql(stage: EtlStage, sql: impl AsRef<str>, msg: impl AsRef<str>) -> Self {
        Error::Sql {
            stage,
            sql: sql.as_ref().to_owned(),
            msg: msg.as_ref().to_owned(),
        }
    }
    pub fn from_big_table(
        file_name: impl AsRef<str>,
        import_name: impl AsRef<str>,
        msg: impl AsRef<str>,
    ) -> Self {
        Error::BigTable {
            file_name: file_name.as_ref().to_owned(),
            import_name: import_name.as_ref().to_owned(),
            msg: msg.as_ref().to_owned(),
        }
    }
}
